#include "VSNode.h"
#include "VSMath.h"
#include "VSGeometry.h"
#include "VSGraphicInclude.h"
#include "VSStream.h"
using namespace VSEngine2;
IMPLEMENT_RTTI(VSNode,VSSpatial)
BEGIN_ADD_PROPERTY(VSNode,VSSpatial)
REGISTER_PROPERTY(m_pChild,Child,VSProperty::F_SAVE_LOAD_CLONE)
REGISTER_PROPERTY(m_pNeedDrawNode,NeedDrawNode,VSProperty::F_SAVE_LOAD_CLONE)
END_ADD_PROPERTY
IMPLEMENT_INITIAL_BEGIN(VSNode)
IMPLEMENT_INITIAL_END
VSNode::VSNode()
{
	DeleteAllChild();

}
VSNode::~VSNode()
{
	DeleteAllChild();
}

unsigned int VSNode::AddChild(VSSpatial * pChild)
{
	if(!pChild)
		return VSMAX_INTEGER;
	for (unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		if (m_pChild[i] == pChild)
		{
			return i;
		}
	}
	pChild->SetParent(this);	
	m_pChild.AddElement(pChild);
	VSNode * pNode = DynamicCast<VSNode>(pChild);
	if (pNode)
	{
		AddNeedDrawNode(pNode);
	}
	
	return m_pChild.GetNum() - 1;
}
unsigned int VSNode::DeleteChild(VSSpatial *pChild)
{
	if(!pChild)
		return VSMAX_INTEGER;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		
		if(m_pChild[i] == pChild)
		{
			VSNode * pNode = DynamicCast<VSNode>(pChild);
			if (pNode)
			{
				DeleteNeedDrawNode(pNode);
			}
			pChild->SetParent(NULL);
			m_pChild.Erase(i);
			return i;
		}
	}

	return VSMAX_INTEGER;
}
bool VSNode::DeleteChild(unsigned int i)
{
	if(i >= m_pChild.GetNum())
		return 0;
	VSSpatial * Temp = m_pChild[i];

	VSNode * pNode = DynamicCast<VSNode>(Temp);
	if (pNode)
	{
		DeleteNeedDrawNode(pNode);
	}
	

	Temp->SetParent(NULL);
	m_pChild.Erase(i);


	return 1;
}

VSSpatial * VSNode::GetChild(unsigned int i)const
{
	if(i >= (unsigned int)m_pChild.GetNum())
		return NULL;
	return m_pChild[i];
}

void VSNode::DeleteAllChild()
{
	
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		VSNode * pNode = DynamicCast<VSNode>(m_pChild[i]);
		if (pNode)
		{
			DeleteNeedDrawNode(pNode);
		}

		m_pChild[i]->SetParent(NULL);
	}
	m_pChild.Clear();
}
void VSNode::UpDateView(VSCuller & Culler,double dAppTime)
{
	VSSpatial::UpDateView(Culler,dAppTime);
}
void VSNode::UpdateWorldBound(double dAppTime)
{
	bool bFoundFirstBound = false; 
	for (unsigned int i = 0; i < m_pChild.GetNum(); i++) 
	{ 	
		if(m_pChild[i])
		{
			if(!bFoundFirstBound)
			{
				m_WorldBV = m_pChild[i]->m_WorldBV;
				bFoundFirstBound = true; 
			}
			else
			{

				m_WorldBV = m_WorldBV.MergAABB(m_pChild[i]->m_WorldBV);
			}
		}

	} 
	


}
void VSNode::UpdateLightState(double dAppTime)
{
	UpdateLightAll(dAppTime);
	if(m_pAllLight.GetNum() > 0)
		m_pAllLight.Clear();
	if(m_pLight.GetNum() > 0)
		m_pAllLight.AddElement(m_pLight,0,m_pLight.GetNum() - 1);
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		if(m_pChild[i])
		{
			if(m_pChild[i]->m_pAllLight.GetNum() > 0)
				m_pAllLight.AddElement(m_pChild[i]->m_pAllLight,0,m_pChild[i]->m_pAllLight.GetNum() - 1);
		}

		
	}
}
void VSNode::UpdateCameraState(double dAppTime)
{
	UpdateCameraAll(dAppTime);
	if(m_pAllCamera.GetNum() > 0)
		m_pAllCamera.Clear();
	if(m_pCamera.GetNum() > 0)
		m_pAllCamera.AddElement(m_pCamera,0,m_pCamera.GetNum() - 1);
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		if(m_pChild[i])
		{
			if(m_pChild[i]->m_pAllCamera.GetNum() > 0)
				m_pAllCamera.AddElement(m_pChild[i]->m_pAllCamera,0,m_pChild[i]->m_pAllCamera.GetNum() - 1);
		}

	}
}
void VSNode::UpdateNodeAll(double dAppTime)
{
	if (!m_bEnable)
	{
		return;
	}
	if (dAppTime > 0.0f)
	{
		UpdateController(dAppTime);
	}
	

	UpdateTransform(dAppTime);
		






	for (unsigned int i = 0; i < m_pChild.GetNum(); i++)	
	{ 
		if (m_pChild[i]) 
			m_pChild[i]->UpdateNodeAll(dAppTime); 
	} 


	UpdateLightState(dAppTime);


	

		
	UpdateCameraState(dAppTime);

	if (dAppTime > 0.0f)
	{
		UpdateOther(dAppTime);
	}



	if(m_bIsChanged)
	{
		UpdateWorldBound(dAppTime); 
	}
	m_bIsChanged = false;
	
}
void VSNode::ComputeNodeVisibleSet(VSCuller & Culler,bool bNoCull,double dAppTime)
{

	UpDateView(Culler,dAppTime);
	if (bNoCull && m_pNeedDrawNode.GetNum() > 0)
	{
		for (unsigned int i = 0 ; i < m_pNeedDrawNode.GetNum() ; i++)
		{
			if (m_pNeedDrawNode[i])
			{
				m_pNeedDrawNode[i]->ComputeVisibleSet(Culler,bNoCull,dAppTime);
			}
		}
	}
	else
	{
		for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
		{
			if(m_pChild[i])
			{

				m_pChild[i]->ComputeVisibleSet(Culler,bNoCull,dAppTime);

			}

		}
	}
	

}
bool VSNode::Register(VSStream & rStream)const
{
	if (rStream.IsObjectRegister(this))
	{
		return 1;
	}
	if(!VSSpatial::Register(rStream))
		return 0;
// 	if(!m_pChild.GetNum())
// 		return 0;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		if(m_pChild[i])
		{
			if(!m_pChild[i]->Register(rStream))
				return 0;
		
		}
	
	}
	for (unsigned int i = 0 ; i < m_pNeedDrawNode.GetNum() ; i++)
	{
		if (m_pNeedDrawNode[i])
		{
			if (!m_pNeedDrawNode[i]->Register(rStream))
			{
				return 0;
			}
		}
	}
	return 1;
}
unsigned int VSNode::DiskUse()const
{
	unsigned int Used = VSSpatial::DiskUse();

	Used += sizeof(VSSpatial *) * m_pChild.GetNum();
	Used += sizeof(VSNode *) * m_pNeedDrawNode.GetNum();
	Used += sizeof(unsigned int);
	Used += sizeof(unsigned int);
	return Used;
}
bool VSNode::Save(VSStream & rStream,unsigned int &iSaveUse)const
{
	if(!VSSpatial::Save(rStream,iSaveUse))
		return 0;
	unsigned int uiChildNum = m_pChild.GetNum();

	if(!rStream.Write(&uiChildNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiChildNum ; i++)
	{
// 		VSSpatial * pChild = m_pChild[i];
// 		if(!rStream.Write(&pChild,sizeof(VSSpatial *)))
// 			return 0;
		if(!rStream.WriteObjectPtr(m_pChild[i]))
			return 0;
		iSaveUse += sizeof(VSSpatial *);
	}

	unsigned int uiDrawNeedNum = m_pNeedDrawNode.GetNum();

	if(!rStream.Write(&uiDrawNeedNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);

	for(unsigned int i = 0 ; i < uiDrawNeedNum ; i++)
	{
		// 		VSSpatial * pChild = m_pChild[i];
		// 		if(!rStream.Write(&pChild,sizeof(VSSpatial *)))
		// 			return 0;
		if(!rStream.WriteObjectPtr(m_pNeedDrawNode[i]))
			return 0;
		iSaveUse += sizeof(VSNode *);
	}
	return 1;
}
bool VSNode::Load(VSStream & rStream,unsigned int &iSaveUse)
{	
	if(!VSSpatial::Load(rStream,iSaveUse))
		return 0;
	unsigned int uiChildNum;
	if(!rStream.Read(&uiChildNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);
	m_pChild.SetBufferNum(uiChildNum);
	for(unsigned int i = 0 ; i < uiChildNum ; i++)
	{
// 		VSSpatial * Temp;
// 		if(!rStream.Read(&Temp,sizeof(VSSpatial *)))
// 			return 0;
// 		AddLink(Temp);
		if(!rStream.ReadObjectPtr(m_pChild[i]))
			return 0;
		iSaveUse += sizeof(VSSpatial *);
	}


	unsigned int uiDrawNeedNum;
	if(!rStream.Read(&uiDrawNeedNum,sizeof(unsigned int)))
		return 0;
	iSaveUse += sizeof(unsigned int);
	m_pNeedDrawNode.SetBufferNum(uiDrawNeedNum);
	for(unsigned int i = 0 ; i < uiDrawNeedNum ; i++)
	{
		// 		VSSpatial * Temp;
		// 		if(!rStream.Read(&Temp,sizeof(VSSpatial *)))
		// 			return 0;
		// 		AddLink(Temp);
		if(!rStream.ReadObjectPtr(m_pNeedDrawNode[i]))
			return 0;
		iSaveUse += sizeof(VSNode *);
	}
	return 1;
}
bool VSNode::Link(VSStream & rStream)
{
	if(!VSSpatial::Link(rStream))
		return 0;
// 	if(!m_pChild.GetNum())
// 		return 0;
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{
		
		//m_pChild[i] = (VSSpatial *)rStream.GetMapValue(GetNextLink());
		rStream.LinkObjectPtr(m_pChild[i]);
		if(!m_pChild[i])
			return 0;


	}

	for(unsigned int i = 0 ; i < m_pNeedDrawNode.GetNum() ; i++)
	{

		//m_pChild[i] = (VSSpatial *)rStream.GetMapValue(GetNextLink());
		rStream.LinkObjectPtr(m_pNeedDrawNode[i]);
		if(!m_pNeedDrawNode[i])
			return 0;


	}
	return 1;
	
}
bool VSNode::Clone(const VSObject *pObject,unsigned int uiType)
{
	const VSNode* Temp = DynamicCast<VSNode>(pObject); 
	if(!Temp)
		return 0;
// 	if(Temp->m_pChild.GetNum() == 0)
// 		return 0;
	if(VSSpatial::Clone(pObject,uiType))
	{

		m_pChild.Clear();
		m_pChild.SetBufferNum(Temp->m_pChild.GetNum());
		for(unsigned int i = 0 ; i < Temp->m_pChild.GetNum() ; i++)
		{
			VSSpatial * pTemp1  = Temp->m_pChild[i];
			VSSpatial * pTemp2 =(VSSpatial *)VSObject::GetInstance((pTemp1)->GetType().GetName());
			pTemp2->SetParent(this);
			pTemp2->Clone(pTemp1,uiType);
			
			m_pChild[i] = pTemp2;
		}
		m_pNeedDrawNode.SetBufferNum(Temp->m_pNeedDrawNode.GetNum());
		for (unsigned int j = 0 ; j < Temp->m_pNeedDrawNode.GetNum() ;j++)
		{
			for (unsigned int i = 0 ; i < Temp->m_pChild.GetNum() ; i++)
			{
				if (Temp->m_pChild[i] == Temp->m_pNeedDrawNode[j])
				{
					VSSpatial * p = m_pChild[i];
					m_pNeedDrawNode[j] = (VSNode *)p;
				}
			}
		}
		return 1;
	
	}
	else
	{
		return 0;
	}

}
bool VSNode::SetLodDesirePercent(VSREAL fDesirePercent)
{
	if (!VSSpatial::SetLodDesirePercent(fDesirePercent))
	{
		return false;
	}
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{

		if(!m_pChild[i]->SetLodDesirePercent(fDesirePercent))
			return false;

	}
	return true;
}
void VSNode::CreateClodMesh()
{
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{

		m_pChild[i]->CreateClodMesh();

	}
}
void VSNode::SetIsVisibleUpdate(bool bIsVisibleUpdate)
{
	for(unsigned int i = 0 ; i < m_pChild.GetNum() ; i++)
	{

		m_pChild[i]->SetIsVisibleUpdate(bIsVisibleUpdate);

	}
}
void VSNode::AddNeedDrawNode(VSNode *pNeedDrawNode)
{	
	if (pNeedDrawNode)
	{
		if(pNeedDrawNode->GetIsNeedDraw() == false)
			return ;

		VSNode * pNode = DynamicCast<VSNode>(m_pParent);
		
		if (pNode)
		{
			pNode->AddNeedDrawNode(pNeedDrawNode);
		}
		unsigned int i = m_pNeedDrawNode.FindElement(pNeedDrawNode);
		if (i >= m_pNeedDrawNode.GetNum())
		{
			m_pNeedDrawNode.AddElement(pNeedDrawNode);
		}
	}

}
void VSNode::DeleteNeedDrawNode(VSNode *pNeedDrawNode)
{
	if (pNeedDrawNode)
	{
		if(pNeedDrawNode->GetIsNeedDraw() == false)
			return ;

		VSNode * pNode = DynamicCast<VSNode>(m_pParent);
		if (pNode)
		{
			pNode->DeleteNeedDrawNode(pNeedDrawNode);
		}
		unsigned int i = m_pNeedDrawNode.FindElement(pNeedDrawNode);
		if (i < m_pNeedDrawNode.GetNum())
		{
			m_pNeedDrawNode.Erase(i);
		}
		
	}
}